#include "Worker.h"
#include "Draft.h"
#include "Tags.h"
#include "ChannelFactory.h"
#include "Logger.h"


Worker::Worker(const QString& algorithmPath, int stopTimeout, QObject* parent) 
: _stopTimeout(stopTimeout)
, _draft(Draft::FromFile(&QFile(algorithmPath)))
, _stop(false)
{
    connect(this, SIGNAL(failure()), parent, SLOT(OnFailure()));
    connect(this, SIGNAL(success()), parent, SLOT(OnSuccess()));
    
    logger.addn(Draft::LastError());
    _draft ? emit success() : emit failure();
}

void Worker::ConstructChannels(const StringMapMap& channels)
{
    Q_FOREACH(const QString& channelName, channels.keys())
        _channels[channelName] = ChannelFactory::Instance().CreateChannel(channels[channelName][tag::AType], channels[channelName]); 
}

bool Worker::EstablishConnections()
{
    logger.addn("Connecting...");

    for (QList<ISimpleChannelPtr> channels = _channels.values(); !_stop && !channels.isEmpty();)
    {
        if (channels.first()->IsOpened() || channels.first()->Open()) 
        {
            logger.addn("Channel connected: " + channels.first()->Info());
            channels.removeFirst();   
        }
    }

    return !_stop;
}

void Worker::run()
{
    if (_draft)
    {
        ConstructChannels(_draft->Channels());
        _machine.reset(new Machine(_draft, _channels));
        connect(_machine.get(), SIGNAL(stopped()), this, SLOT(quit()), Qt::DirectConnection); //exit thread's event loop when machine stops
        
        while(!_stop && EstablishConnections()) 
        {
            _machine->Start();
            exec();
        }
    }
}

void Worker::Stop(bool gentle)
{
    logger.addn(gentle ? "Exit signal." : "Abort signal.");
    _stop = true;

	if (_machine)
        _machine->Stop(gentle);
    
    if (!wait(_stopTimeout))
    {
        terminate();
        logger.addn("Worker terminated.");
    }
    
    logger.addn("Worker stopped.");
}
